# -*- coding: utf8 -*-

import json
from random import randint

from google.appengine.ext import ndb
from google.appengine.api import memcache
from constants import MAX_PIN_LENGTH, MIN_PIN_LENGTH


class WrongPincodeError(Exception):
    pass


class Settings(ndb.Model):
    time_per_round_sec = ndb.IntegerProperty(indexed=False)
    skip_words_per_round = ndb.IntegerProperty(indexed=False)
    time_before_out_sec = ndb.IntegerProperty(indexed=False)
    word_count = ndb.IntegerProperty(indexed=False)

    def __init__(self, **kwargs):
        super(Settings, self).__init__(**kwargs)
        if not hasattr(self, 'word_count') or self.word_count is None:
            self.word_count = 10


class GameTemplate(ndb.Model):
    owner_email = ndb.StringProperty()
    name = ndb.StringProperty()
    is_joinable = ndb.BooleanProperty()
    players = ndb.StringProperty(repeated=True, indexed=False)
    words = ndb.StringProperty(repeated=True, indexed=False)
    owners = ndb.IntegerProperty(repeated=True, indexed=False)
    settings = ndb.StructuredProperty(Settings, indexed=False)
    id_ = ndb.IntegerProperty()
    pin_code = ndb.IntegerProperty(indexed=False)
    last_pushed_player = ndb.IntegerProperty(indexed=False)
    last_pushed_word = ndb.IntegerProperty(indexed=False)

    def __init__(self, **kwargs):
        super(GameTemplate, self).__init__(**kwargs)
        self.last_pushed_word = -1
        self.last_pushed_player = -1
        self.pin_code = randint(10 ** (MIN_PIN_LENGTH - 1),
                                10 ** MAX_PIN_LENGTH - 1)
        if self.is_joinable is None:
            self.is_joinable = False
        if self.settings is None:
            self.settings = Settings()

    """ stores players and words for a new game
    players: (ndb.StringProperty(repeated=True))
    words: (ndb.StringProperty(repeated=True))
    settings: (ndb.StructuredProperty(Settings))
    id_: (ndb.IntegerProperty()) unique game id
    pin_code: (ndb.IntegerProperty()) pin code need to get game
    """

    def make_json(self):
        all_json = {
            u'is_joinable': self.is_joinable,
            u'players': [],
            u'hat': [],
            u'remote_id': self.id_,
            u'settings': {
                u'skip_words_per_round': self.settings.skip_words_per_round,
                u'time_before_out_sec': self.settings.time_before_out_sec,
                u'time_per_round_sec': self.settings.time_per_round_sec,
                u'word_count': self.settings.word_count
            }
        }
        for word in self.words:
            all_json[u'hat'].append({u'text': word, u'owner': None})
        for player in self.players:
            all_json[u'players'].append(player)
        return unicode(json.dumps(all_json, sort_keys=True).encode("utf-8"))

    def make_added_players_json(self):
        self.last_pushed_player += 1
        self.last_pushed_word += 1
        all_json = {
            u'players': [],
            u'hat': []
        }
        for i in range(self.last_pushed_word, len(self.words)):
            all_json[u'hat'].append({u'text': self.words[i],
                                     u'owner': self.owners[i]})
        for player in self.players[self.last_pushed_player:]:
            all_json[u'players'].append(player)
        self.last_pushed_word = len(self.words) - 1
        self.last_pushed_player = len(self.players) - 1
        return unicode(json.dumps(all_json, sort_keys=True).encode("utf-8"))

    def make_id_pin_json(self):
        id_json = {
            u'id': self.id_,
            u'pin': self.pin_code
        }
        return unicode(json.dumps(id_json, sort_keys=True).encode("utf-8"))

    @staticmethod
    def get_by_id(game_id, pin_code):
        game_key = memcache.get('game_by_id_' + str(game_id))
        if game_key is not None:
            game = game_key.get()
        else:
            query_result =\
                GameTemplate.query().filter(GameTemplate.id_ == game_id)
            game = query_result.get()
            if game is None:
                return None
            memcache.set('game_by_id_' + str(game_id), game.key)
        if game.pin_code != pin_code:
            raise WrongPincodeError('Pincode is incorrect %s' % pin_code)
        return game

    @staticmethod
    def get_new_id():
        new_id = memcache.incr('game_id_count')
        if new_id is None:
            last_game = GameTemplate.query().order(-GameTemplate.id_).get()
            if last_game is None:
                new_id = 0
            else:
                new_id = last_game.id_ + 1
            memcache.set('game_id_count', new_id)
        return new_id

    def put(self):
        super(GameTemplate, self).put()
        memcache.set('game_by_id_' + str(self.id_), self.key)
